UIView动画事务

简介

  • 日常开发中常使用动画,恰当地使用动画有助于提高用户体验。
  • UIView动画事务提供了大量简单的接口来实现种类繁多的动画效果。
  • UIView动画事务多用于执行隐式动画:
    frame:设置视图大小及位置
    bounds:设置视图矩形大小
    center:设置视图中心点位置
    transform:设置视图的纺射变幻属性(缩放、旋转)
    alpha:设置视图的透明度
    

    UIView动画事务基本要素

  • 持续时间:Duration,描述了动画执行的总时间。
  • 线性规律:Curve,描述了动画的执行方式,展示的效果。
  • 动画类型:通过改变视图属性,生成隐式动画效果。
  • 回调方法:动画委托方法或选取器方法,可以监视动画执行状态,并在相应状态执行自定义操作。
  • 其他配置:UIView动画事务提供了更多的配置接口,使动画效果更多样化。

UIView动画事务的初始化及配置

  • 一般方法配置动画事务
1
2
3
4
5
6
7
8
9
10
11
12
+(void)beginAnimations:(NSString *)animationID context:(void *)context;
+(void)commitAnimations;

[UIView beginAnimations:@"alpha" context:nil];

// 动画事务配置代码:
// 持续时间;
// 线性规律;
// 重复次数;
// ......

[UIView commitAnimations];
  • 使用block代码块实现动画事务
1
2
3
4
5
6
7
8
9
10
+(void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations;
[UIView animateWithDuration:1.0 animations:^{

// 动画事务配置代码:
// 持续时间;
// 线性规律;
// 重复次数;
// ......

}];

UIView转场动画及委托回调配置

  • +(void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;
    UIViewAnimationTransition:
    UIViewAnimationTransitionNone:无转场动画类型
    UIViewAnimationTransitionFlipFromLeft:页面从左向右翻转
    UIViewAnimationTransitionFlipFromRight:页面从右向左翻转
    UIViewAnimationTransitionCurlUp:向上翻页
    UIViewAnimationTransitionCurlDown:向下翻页
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
设置委托
+ (void)setAnimationDelegate:(id)delegate;
动画开始回调方法
+ (void)setAnimationWillStartSelector:(SEL)selector;
动画结束回调方法
+ (void)setAnimationDidStopSelector:(SEL)selector;
动画回调方法声明(以动画结束回调为例)
// animationID:标识符,用于判断当前结束的动画是哪一个
// finished:动画结束
// context:上下文

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context;
+ (void)setAnimationDidStopSelector:(SEL)selector;
动画事务block生成回调方法
[UIView animateWithDuration:1.0 animations:^{
// 配置动画
} completion:^(BOOL finished) {
// 动画回调
}];
  • Tips:
    如果需要实现组合动画,对于动画事务一般生成方法,需要设置代理,并且声明回调方法,在回调方法中根据 AnimationId 判断当前结束的是哪一个动画,然后根据需求执行下一个动画方法;而对于动画事务block生成方法,无需声明回调方法,直接在 completion 块中执行动画结束后的操作即可(即执行下一个动画)。

一般动画事务生成方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
#import "UIViewAnimationsViewController.h"

// 动画持续时间
static NSTimeInterval const animationDuration = 1.0;

// animation ids
static NSString *const kUIViewAnimationTypePosition = @"position";
static NSString *const kUIViewAnimationTypeScale = @"scale";
static NSString *const kUIViewAnimationTypeRotate = @"rotate";
static NSString *const kUIViewAnimationTypeColor = @"color";
static NSString *const kUIViewAnimationTypeAlpha = @"alpha";
static NSString *const kUIViewAnimationTypeEnd = @"end";

@interface UIViewAnimationsViewController ()

{
UIView *_animationsView;
}

@property (nonatomic, copy) UIView *animationsView; /**< 动画视图 */

- (void)initializeUserInterface; /**< 初始化用户界面 */

// 1、UIView动画事务一般生成

- (void)positionAnimation;
- (void)scaleAnimation;
- (void)rotateAnimation;
- (void)colorAnimation;
- (void)alphaAnimation;
- (void)endAnimations;

// 动画结束回调方法
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context;

@end

@implementation UIViewAnimationsViewController

- (void)dealloc
{
[_animationsView release]; _animationsView = nil;

[super dealloc];
}

- (void)viewDidLoad {
[super viewDidLoad];
[self initializeUserInterface];
}

#pragma mark *** Initialize methods ***

- (instancetype)init {
if (self = [super init]) {
self.title = @"ViewAnimations";
}
return self;
}

- (void)initializeUserInterface {
self.view.backgroundColor = [UIColor whiteColor];

[self.view addSubview:self.animationsView];


// 添加点击手势,触发动画
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToGesture:)];
[_animationsView addGestureRecognizer:tap];

[tap release];


}

#pragma mark *** UIView动画事务一般生成 ***

/**
* 动画基本要素:持续时间,线性规律,动画类型,回调方法,其他配置
*/

- (void)positionAnimation {
// 一般动画事务生成方法
[UIView beginAnimations:kUIViewAnimationTypePosition context:nil];
// 持续时间
[UIView setAnimationDuration:animationDuration];
// 线性规律
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
// 动画回调
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
// 其他配置
// [UIView setAnimationRepeatCount:HUGE_VAL]; // 动画重复次数
// [UIView setAnimationRepeatAutoreverses:YES]; // 设置动画是否方向执行

// 动画类型
_animationsView.center = self.view.center;

// 提交动画
[UIView commitAnimations];
}

- (void)scaleAnimation {
[UIView beginAnimations:kUIViewAnimationTypeScale context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

// 动画类型
// 缩放、旋转动画使用transform属性
// _animationView.transform = CGAffineTransformScale(_animationView.transform, 1.5, 1.5);
_animationsView.transform = CGAffineTransformMakeScale(1.5, 1.5);
[UIView commitAnimations];
}

- (void)rotateAnimation {
[UIView beginAnimations:kUIViewAnimationTypeRotate context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

// 动画类型
/*
* M_PI:表示π,180度的弧度表示
* M_PI_2:M_PI / 2
* M_PI_4:M_PI / 4
* CGAffineTransformMake...:新生成一个变幻属性,覆盖之前的.
* CGAffineTransform...:在视图之前变幻属性的基础之上再进行变幻
*/
_animationsView.transform = CGAffineTransformRotate(_animationsView.transform, M_PI_2);
[UIView setAnimationRepeatCount:HUGE_VAL];

[UIView commitAnimations];
}

- (void)colorAnimation {
[UIView beginAnimations:kUIViewAnimationTypeColor context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

_animationsView.backgroundColor = [UIColor redColor];

[UIView commitAnimations];
}

- (void)alphaAnimation {
[UIView beginAnimations:kUIViewAnimationTypeAlpha context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

_animationsView.alpha = 0.5;

[UIView commitAnimations];
}

- (void)endAnimations {
[UIView beginAnimations:kUIViewAnimationTypeEnd context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

// 同一动画事务多个动画同时执行

/*
* UIView动画事务转场动画:
* UIViewAnimationTransitionCurlUp 上翻页效果
* UIViewAnimationTransitionCurlDown 下翻页效果
*/

_animationsView.backgroundColor = [UIColor blackColor];
_animationsView.alpha = 1;
_animationsView.center = CGPointMake(CGRectGetMinX(self.view.bounds) + CGRectGetMidX(_animationsView.bounds),
CGRectGetMinY(self.view.bounds) + CGRectGetMidY(_animationsView.bounds) + 64);
// CGAffineTransformIdentity:将视图的transform属性重置,清除任何放射变幻属性 *
_animationsView.transform = CGAffineTransformIdentity;

[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:_animationsView cache:NO];
[UIView commitAnimations];

}

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
if ([animationID isEqualToString:kUIViewAnimationTypePosition]) {
[self scaleAnimation];
}else if ([animationID isEqualToString:kUIViewAnimationTypeScale]){
[self rotateAnimation];
}else if ([animationID isEqualToString:kUIViewAnimationTypeRotate]){
[self colorAnimation];
}else if ([animationID isEqualToString:kUIViewAnimationTypeColor]){
[self alphaAnimation];
}else if ([animationID isEqualToString:kUIViewAnimationTypeAlpha]){
[self endAnimations];
}
}
#pragma mark *** Gestures ***
- (void)respondsToGesture:(UITapGestureRecognizer *)gesture {
NSLog(@"%@", NSStringFromSelector(_cmd));

// 1、UIView动画一般事务
[self positionAnimation];
}

#pragma mark *** Getters ***
- (UIView *)animationsView {
if (!_animationsView) {
_animationsView = [[[UIView alloc] init] autorelease];
_animationsView.bounds = CGRectMake(0, 0, 160, 160);
_animationsView.center = CGPointMake(CGRectGetMidX(_animationsView.bounds), CGRectGetMidY(_animationsView.bounds) + 64);
_animationsView.backgroundColor = [UIColor blackColor];
}
return _animationsView;
}


@end
Block实现

#import "UIViewAnimationsViewController.h"

static NSTimeInterval const animationDuration = 1.0;

@interface UIViewAnimationsViewController ()

{
UIView *_animationsView;
}

@property (nonatomic, copy) UIView *animationsView; /**< 动画视图 */

- (void)initializeUserInterface; /**< 初始化用户界面 */

// 1、UIView动画事务block生成
- (void)positionAnimationBlock;
- (void)scaleAnimationBlock;
- (void)rotateAnimationBlock;
- (void)colorAnimationBlock;
- (void)alphaAnimationBlock;
- (void)endAnimationsBlock;

@end

@implementation UIViewAnimationsViewController

- (void)dealloc
{
[_animationsView release]; _animationsView = nil;

[super dealloc];
}

- (void)viewDidLoad {
[super viewDidLoad];
[self initializeUserInterface];
}

#pragma mark *** Initialize methods ***

- (instancetype)init {
if (self = [super init]) {
self.title = @"ViewAnimations";
}
return self;
}

- (void)initializeUserInterface {
self.view.backgroundColor = [UIColor whiteColor];

[self.view addSubview:self.animationsView];


// 添加点击手势
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToGesture:)];
[_animationsView addGestureRecognizer:tap];

[tap release];


}

#pragma mark *** UIView动画事务block生成 ***

- (void)positionAnimationBlock {
/**
* animateWithDuration:持续时间
* delay:延迟
* options:可选,配置线性规律
* animations:动画类型
* completion:动画回调
*/
[UIView animateWithDuration:animationDuration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
// 处理动画类型及基本配置
_animationsView.center = self.view.center;
} completion:^(BOOL finished) {
// 动画执行完后回调方法
[self scaleAnimationBlock];
}];
}

- (void)scaleAnimationBlock {
[UIView animateWithDuration:animationDuration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
// _animationView.transform = CGAffineTransformScale(_animationView.transform, 1.5, 1.5);
_animationsView.transform = CGAffineTransformMakeScale(1.5, 1.5);
} completion:^(BOOL finished) {
[self rotateAnimationBlock];
}];
}

- (void)rotateAnimationBlock {
[UIView animateWithDuration:animationDuration delay:0.0 options:(UIViewAnimationOptionCurveLinear) animations:^{
_animationsView.transform = CGAffineTransformRotate(_animationsView.transform, M_PI);
} completion:^(BOOL finished) {
[self colorAnimationBlock];
}];
}

- (void)colorAnimationBlock {
[UIView animateWithDuration:animationDuration delay:0.0 options:(UIViewAnimationOptionCurveLinear) animations:^{
_animationsView.backgroundColor = [UIColor redColor];
} completion:^(BOOL finished) {
[self alphaAnimationBlock];
}];
}

- (void)alphaAnimationBlock {
[UIView animateWithDuration:animationDuration delay:0.0 options:(UIViewAnimationOptionCurveLinear) animations:^{
_animationsView.alpha = 0.5;
} completion:^(BOOL finished) {
[self endAnimationsBlock];
}];
}

- (void)endAnimationsBlock {
[UIView animateWithDuration:animationDuration delay:0.0 options:(UIViewAnimationOptionCurveLinear) animations:^{
_animationsView.center = CGPointMake(CGRectGetMinX(self.view.bounds) + CGRectGetMidX(_animationsView.bounds),
CGRectGetMinY(self.view.bounds) + CGRectGetMidY(_animationsView.bounds) + 64);
_animationsView.backgroundColor = [UIColor blackColor];
_animationsView.alpha = 1;
_animationsView.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished) {

}];
}
#pragma mark *** Gestures ***
- (void)respondsToGesture:(UITapGestureRecognizer *)gesture {
NSLog(@"%@", NSStringFromSelector(_cmd));

// 1、UIView动画一般事务
[self positionAnimationBlock];
}

#pragma mark *** Getters ***
- (UIView *)animationsView {
if (!_animationsView) {
_animationsView = [[[UIView alloc] init] autorelease];
_animationsView.bounds = CGRectMake(0, 0, 160, 160);
_animationsView.center = CGPointMake(CGRectGetMidX(_animationsView.bounds), CGRectGetMidY(_animationsView.bounds) + 64);
_animationsView.backgroundColor = [UIColor blackColor];
}
return _animationsView;
}


@end

UIImageView动画

  • UIImageView是图片展示视图,除了展示图片功能之外,也可以用于实现动画效果。
  • 动画配置

    animationImages:设置动画图片数组
    animationDuration:设置动画持续时长
    animationRepeatCount:设置动画重复次数,默认为0无限次重复
    
  • 常用方法

    开始执行动画
    - (void)startAnimating; 
    
    结束执行动画
    - (void)stopAnimating;
    

UIImageView动画代码案例

  • 初始化UIImageView动画
1
2
3
4
5
6
7
8
9
10
- (void)initializeImageAnimations {
// 持续时间
_imageAnimationsView = 5.0;
// 图片数据源,_images为存储UIImage对象的数组。
_imageAnimationsView = _images;
// 重复次数
_imageAnimationsView = 0;
// 开始动画
[_imageAnimationsView startAnimating];
}
  • 触摸拖动_imageAnimationsView视图方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 触摸移动
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"%@", NSStringFromSelector(_cmd));
// 根据移动的轨迹移动图片视图
UITouch *touch = [touches anyObject];
if (touch.view == _imageAnimationsView) {
// 获取上一个点
CGPoint previousLocation = [touch previousLocationInView:_imageAnimationsView];
// 获取当前点
CGPoint currentLocation = [touch locationInView:_imageAnimationsView];
// 获取偏移
CGPoint offset = CGPointMake(currentLocation.x - previousLocation.x, currentLocation.y - previousLocation.y);

// 更新图片视图中心点
_imageAnimationsView.center = CGPointMake(_imageAnimationsView.center.x + offset.x, _imageAnimationsView.center.y + offset.y);

}
}

动画事件

有时需要在某一个视图执行动画的过程中(比如位置移动)实现点击效果,如果通过添加手势的方式,会发现,即使开启了用户交互userInteractionEnabled也不会达到预期的效果,这是由于UIView动画事务执行的是隐式动画,因此不能通过手势的方式,而应该通过触摸的方式处理逻辑,此处模拟动画在移动过程中实现点击效果,animatingView为添加UIView动画事务移动的的动画。直接上关键代码;

1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma mark *** Touches ***

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

UITouch *touch = [touches anyObject];

CGPoint location = [touch locationInView:self.view];

if ([self.animatingView.layer.presentationLayer hitTest:location]) {

NSLog(@"User clicked view.");
}
}